package codename.primavera.web.exception;

import java.util.Iterator;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.application.NavigationHandler;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.security.access.AccessDeniedException;

/**
 * New in JSF2 is the {@link ExceptionHandler}. This class is the custom
 * implementation of the {@link ExceptionHandlerWrapper} that will handle
 * specific Application Exceptions. All exceptions are queued internaly and
 * can be processed here. Once you handle an exception here, you can decide
 * to either let it pass again through the wrapped {@link ExceptionHandler}
 * , or remove it from the queue. Choose the latter when possible,
 * exceptions should only be processed once.
 * @see ExceptionHandler
 * @see ExceptionHandlerWrapper
 * @author sander
 */
/**
 * @author sander
 */
public class PrimaveraExceptionHandler extends ExceptionHandlerWrapper {

    /**
     * the wrapped.
     */
    private ExceptionHandler wrapped;

    /**
     * Constructor will be called by the framework.
     * @param someWrapped the wrapped
     */
    public PrimaveraExceptionHandler(final ExceptionHandler someWrapped) {
        wrapped = someWrapped;
    }

    /** {@inheritDoc} */
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

    /**
     * Overridden implementation of the actual exception handling. Please
     * pay attention to removing the exception from the queue. A default
     * ViewExpiredException-handling is provided.
     * @throws FacesException faces Exception
     * @see ExceptionHandler#handle()
     */
    @Override
    public void handle() throws FacesException {
        for (Iterator < ExceptionQueuedEvent > i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            Throwable t = ExceptionUtils.getRootCause(context.getException());
            if (t instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) t;
                FacesContext fc = FacesContext.getCurrentInstance();
                Map < String, Object > requestMap = fc.getExternalContext().getRequestMap();
                NavigationHandler nav = fc.getApplication().getNavigationHandler();
                try {
                    // Push some useful stuff to the request scope for
                    // use in the page
                    requestMap.put("currentViewId", vee.getViewId());
                    nav.handleNavigation(fc, null, "viewExpired");
                    fc.renderResponse();
                } finally {
                    i.remove();
                }
            } else if (t instanceof AccessDeniedException) {
                // TODO: I18n of this label
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Access denied!"));
                i.remove();
            }
        }
        // Our logic is done, let the wrapped handler continue.
        getWrapped().handle();

    }

}
